home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / technote / tchntstc.sit / Technical Notes Stack 3.2.1 / Technical Notes Stack 3.2.1 / card_23063.txt < prev    next >
Encoding:
Text File  |  1990-01-08  |  10.7 KB  |  248 lines

  1. -- card: 23063 from stack: in.1
  2. -- bmap block id: 0
  3. -- flags: 0000
  4. -- background id: 2711
  5. -- name: 
  6.  
  7.  
  8. -- part contents for background part 9
  9. ----- text -----
  10. #086:    MacPaint Document Format
  11.  
  12. Revised by:    Jim Reekes                                             June 1989
  13. Written by:    Bill Atkinson                                               1983
  14.  
  15. This Technical Note describes the internal format of a MacPaint┬« document, which is a standard used by many other programs.  This description is the same as that found in the ΓÇ£Macintosh MiscellaneousΓÇ¥ section of early Inside Macintosh versions.
  16. Changes since October 1988:  Fixed bugs in the example code.
  17. _______________________________________________________________________________
  18.  
  19. MacPaint documents are easy to read and write, and they have become a standard interchange format for fullΓÇôpage images on the Macintosh.  This Note describes the MacPaint internal document format to help developers generate and interpret files in this format.
  20.  
  21. MacPaint documents have a file type of ΓÇ£PNTG,ΓÇ¥ and since they use only the data fork, you can ignore the resource fork.  The data fork contains a 512ΓÇôbyte header followed by compressed data which represents a single bitmap (576 pixels wide by 720 pixels tall).  At a resolution of 72 pixels per inch, this bitmap occupies the full 8 inch by 10 inch printable area of a standard ImageWriter printer page.
  22.  
  23. Header
  24.  
  25. The first 512 bytes of the document form a header of the following format:
  26.  
  27.   ΓÇó  4ΓÇôbyte version number (default = 2)
  28.   ΓÇó  38*8 = 304 bytes of patterns
  29.   ΓÇó  204 unused bytes (reserved for future expansion)
  30.  
  31. As a Pascal record, the document format could look like the following:
  32.  
  33.     MPHeader = RECORD
  34.         Version:     LONGINT;
  35.         PatArray:    ARRAY [1..38] of Pattern;
  36.         Future:      PACKED ARRAY [1..204] of SignedByte;
  37.     END;
  38.  
  39. If the version number is zero, the document uses default patterns, so you can ignore the rest of the header block, and if your program generates MacPaint documents, you can write 512 bytes of zero for the document header.  Most programs which read MacPaint documents can skip the header when reading.
  40.  
  41. Bitmap
  42.  
  43. Following the header are 720 compressed scan lines of data which form the 576 pixel wide by 720 pixel tall bitmap.  Without compression, this bitmap would occupy 51,840 bytes and chew up disk space pretty fast; typical MacPaint documents compress to about 10K using the _PackBits procedure to compress runs of equal bytes within each scan line.  The bitmap part of a MacPaint document is simply the output of _PackBits called 720 times, with 72 bytes of input each time.
  44.  
  45. To determine the maximum size of a MacPaint file, it is worth noting what Inside Macintosh says about _PackBits:
  46.  
  47.     ΓÇ£The worst case would be when _PackBits adds one byte to the row
  48.     of bytes when packing.ΓÇ¥
  49.  
  50. If we include an extra 512 bytes for the file header information to the size of an uncompressed bitmap (51,840), then the total number of bytes would be 52,352.  If we take into account the extra 720 ΓÇ£potentialΓÇ¥ bytes (one for each row) to the previous total, the maximum size of a MacPaint file becomes 53,072 bytes.
  51.  
  52. Reading Sample
  53.  
  54. PROCEDURE ReadMPFile;
  55. { This is a small example procedure written in Pascal that demonstrates
  56.   how to read MacPaint files. As a final step, it takes the data that
  57.   was read and displays it on the screen to show that it worked.
  58.   Caveat: This is not intended to be an example of good programming
  59.   practice, in that the possible errors merely cause the program to exit.
  60.   This is VERY uninformative, and there should be some sort of error handler
  61.   to explain what happened. For simplicity, and thus clarity, those types
  62.   of things were deliberately not included. This example will not work
  63.   on a 128K Macintosh, since memory allocation is done too simplistically.
  64. }
  65.  
  66. CONST
  67.     DefaultVolume = 0;
  68.     HeaderSize = 512;                      { size of MacPaint header in bytes } 
  69.     MaxUnPackedSize = 51840;               { maximum MacPaint size in bytes }
  70.                                            { 720 lines * 72 bytes/line }
  71. VAR
  72.     srcPtr:      Ptr;
  73.     dstPtr:      Ptr;
  74.     saveDstPtr:  Ptr;
  75.     lastDestPtr: Ptr;
  76.     srcFile:     INTEGER;
  77.     srcSize:     LONGINT;
  78.     errCode:     INTEGER;
  79.     scanLine:    INTEGER;
  80.     aPort:       GrafPort;
  81.     theBitMap:   BitMap;
  82.  
  83. BEGIN
  84.     errCode := FSOpen('MP TestFile', DefaultVolume, srcFile); { Open the file. }
  85.     IF errCode <> noErr THEN ExitToShell;
  86.         
  87.     errcode := SetFPos(srcFile, fsFromStart, HeaderSize);   { Skip the header. }
  88.     IF errCode <> noErr THEN ExitToShell;
  89.  
  90.     errCode := GetEOF(srcFile, srcSize);    { Find out how big the file is, }
  91.     IF errCode <> noErr THEN ExitToShell;   { and figure out source size. }
  92.  
  93.     srcSize := srcSize - HeaderSize ;       { Remove the header from count. }
  94.     srcPtr := NewPtr(srcSize);              { Make buffer just the right size. }
  95.     IF srcPtr = NIL THEN ExitToShell;
  96.         
  97.     errCode := FSRead(srcFile, srcSize, srcPtr);{Read the data into the buffer.}
  98.     IF errCode <> noErr THEN ExitToShell;   { File marker is past header. }
  99.  
  100.     errCode := FSClose(srcFile);            { Close the file we just read. }
  101.     IF errCode <> noErr THEN ExitToShell;
  102.  
  103.     { Create a buffer that will be used for the Destination BitMap. }
  104.     dstPtr := NewPtrClear(MaxUnPackedSize); {MPW library routine, see TN 219}
  105.     IF dstPtr = NIL THEN ExitToShell;
  106.     saveDstPtr := dstPtr;
  107.  
  108.     { Unpack each scan line into the buffer. Note that 720 scan lines are
  109.       guaranteed to be in the file. (They may be blank lines.) In the
  110.       UnPackBits call, the 72 is the count of bytes done when the file was
  111.       created.  MacPaint does one scan line at a time when creating the file.
  112.       The destination pointer is tested each time through the scan loop.
  113.       UnPackBits should increment this pointer by 72, but in the case where
  114.       the packed file is corrupted UnPackBits may end up sending bits into
  115.       uncharted territory.  A temporary pointer "lastDstPtr" is used for
  116.       testing the result.}
  117.  
  118.     FOR scanLine := 1 TO 720 DO BEGIN
  119.          lastDstPtr := dstPtr;
  120.          UnPackBits(srcPtr, dstPtr, 72);    { bumps both pointers }
  121.          IF ORD4(lastDstPtr) + 72 <> ORD4(dstPtr) THEN ExitToShell;
  122.     END;
  123.  
  124.     { The buffer has been fully unpacked. Create a port that we can draw into.
  125.       You should save and restore the current port.  }
  126.     OpenPort(@aPort);
  127.  
  128.     { Create a BitMap out of our saveDstPtr that can be copied to the screen. }
  129.     theBitMap.baseAddr := saveDstPtr;
  130.     theBitMap.rowBytes := 72;               { width of MacPaint picture }
  131.     SetPt(theBitMap.bounds.topLeft, 0, 0);
  132.     SetPt(theBitMap.bounds.botRight, 72*8, 720); {maximum rectangle}
  133.  
  134.     { Now use that BitMap and draw the piece of it to the screen.
  135.       Only draw the piece that is full screen size (portRect). }
  136.     CopyBits(theBitMap, aPort.portBits, aPort.portRect,
  137.              aPort.portRect, srcCopy, NIL);
  138.  
  139.     { We need to dispose of the memory weΓÇÖve allocated.  You would not
  140.       dispose of the destPtr if you wish to edit the data.  }
  141.     DisposPtr(srcPtr);                  { dispose of the source buffer }
  142.     DisposPtr(dstPtr);                  { dispose of the destination buffer }
  143. END;
  144.  
  145.  
  146. Writing Sample
  147.  
  148. PROCEDURE WriteMPFile;
  149. { This is a small example procedure written in Pascal that demonstrates how 
  150.   to write MacPaint files. It will use the screen as a handy BitMap to be
  151.   written to a file.
  152. }
  153.     
  154. CONST
  155.     DefaultVolume = 0;
  156.     HeaderSize = 512;                      { size of MacPaint header in bytes } 
  157.     MaxFileSize = 53072;                   { maximum MacPaint file size. }
  158.  
  159. VAR
  160.     srcPtr:      Ptr;
  161.     dstPtr:      Ptr;
  162.     dstFile:     INTEGER;
  163.     dstSize:     LONGINT;
  164.     errCode:     INTEGER;
  165.     scanLine:    INTEGER;
  166.     aPort:       GrafPort;
  167.     dstBuffer:   PACKED ARRAY[1..HeaderSize] OF BYTE;
  168.     I:           LONGINT;
  169.     picturePtr:  Ptr;
  170.     tempPtr:     BigPtr;
  171.     theBitMap:   BitMap;
  172.     
  173. BEGIN
  174.     { Make an empty buffer that is the picture size. }
  175.     picturePtr := NewPtrClear(MaxFileSize);    {MPW library routine, see TN 219}
  176.     IF picturePtr = NIL THEN ExitToShell;
  177.  
  178.     { Open a port so we can get to the screen's BitMap easily.  You should save
  179.       and restore the current port. }
  180.     OpenPort(@aPort);
  181.  
  182.     { Create a BitMap out of our dstPtr that can be copied to the screen. }
  183.     theBitMap.baseAddr := picturePtr;
  184.     theBitMap.rowBytes := 72;                  { width of MacPaint picture }
  185.     SetPt(theBitMap.bounds.topLeft, 0, 0);
  186.     SetPt(theBitMap.bounds.botRight, 72*8, 720); {maximum rectangle}
  187.  
  188.     { Draw the screen over into our picture buffer. }
  189.     CopyBits(aPort.portBits, theBitMap, aPort.portRect,
  190.              aPort.portRect, srcCopy, NIL);
  191.  
  192.     { Create the file, giving it the right Creator and File type.}
  193.     errCode := Create('MP TestFile', DefaultVolume, 'MPNT', 'PNTG');
  194.     IF errCode <> noErr THEN ExitToShell;
  195.  
  196.     { Open the data file to be written. }
  197.     errCode := FSOpen(dstFileName, DefaultVolume, dstFile);
  198.     IF errCode <> noErr THEN ExitToShell;
  199.  
  200.     FOR I := 1 to HeaderSize DO               { Write the header as all zeros. }
  201.          dstBuffer[I] := 0;
  202.     errCode := FSWrite(dstFile, HeaderSize, @dstBuffer);
  203.     IF errCode <> noErr THEN ExitToShell;
  204.  
  205.  
  206.     { Now go into a loop where we pack each line of data into the buffer,
  207.       then write that data to the file. We are using the line count of 72
  208.       in order to make the file readable by MacPaint. Note that the
  209.       Pack/UnPackBits can be used for other purposes. }
  210.     srcPtr := theBitMap.baseAddr;              { point at our picture BitMap }
  211.     FOR scanLine := 1 to 720 DO
  212.          BEGIN
  213.             dstPtr := @dstBuffer;              { reset the pointer to bottom }
  214.             PackBits(srcPtr, dstPtr, 72);             { bumps both ptrs }
  215.             dstSize := ORD(dstPtr)-ORD(@dstBuffer);   { calc packed size }
  216.             errCode := FSWrite(dstFile, dstSize, @dstBuffer);
  217.             IF errCode <> noErr THEN ExitToShell;
  218.          END;
  219.  
  220.     errCode := FSClose(dstFile);               { Close the file we just wrote. }
  221.     IF errCode <> noErr THEN ExitToShell;
  222. END;
  223.  
  224.  
  225. Further Reference:
  226. _______________________________________________________________________________
  227.   ΓÇó  Inside Macintosh, Volume I-135, QuickDraw
  228.   ΓÇó  Inside Macintosh, Volume I-465, Toolbox Utilities
  229.   ΓÇó  Inside Macintosh, Volume II-77, The File Manager
  230.   ΓÇó  Technical Note #219, New Memory Manager Glue Routines
  231.  
  232. MacPaint is a registered trademark of Claris Corporation.
  233.  
  234.  
  235. -- part contents for background part 2
  236. ----- text -----
  237. 086
  238.  
  239. -- part contents for background part 7
  240. ----- text -----
  241. MacPaint Document Format
  242.  
  243. -- part contents for background part 113
  244. ----- text -----
  245. QuickDraw
  246. Toolbox Utilities
  247. File Manager
  248. Technical Note #219